package com.alibaba.citrus.ots.application.report.ability.facade.service;

import com.alibaba.citrus.ots.application.report.ability.facade.job.MonthSalesStockReportSyncJob;
import com.alibaba.citrus.ots.application.report.ability.repository.MonthSalesStockReportQueryRepository;
import com.alibaba.citrus.ots.application.report.ability.utils.DomUtil;
import com.alibaba.citrus.ots.application.report.ability.utils.SubtotalViewVOUtil;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.DateUtils;
import com.alibaba.cz.base.tool.StringUtil;
import com.alibaba.cz.base.tool.message.ErrorMessage;
import com.alibaba.cz.base.tool.page.PageResult;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lattice2.epoch.middleware.cache.runtime.service.EpochCacheService;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otsapplicationreportsdk.contants.OtsApplicationReportSdkConstants;
import com.epoch.app.otsapplicationreportsdk.model.dto.MonthSalesStockReportSDO;
import com.epoch.app.otsapplicationreportsdk.model.dto.MonthSalesStockReportVO;
import com.epoch.app.otsapplicationreportsdk.model.dto.QueryMonthStockReportRequest;
import com.epoch.app.otsapplicationreportsdk.model.dto.SubtotalViewVO;
import com.epoch.app.otsapplicationreportsdk.model.enums.ScItemGuaranteePeriodTypeEnum;
import com.epoch.app.otsapplicationreportsdk.monthsalesstockreportquery.service.MonthSalesStockReportQueryService;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhoubc
 * @description: TODO
 * @date 2023/3/21 15:51
 */
@Primary
@Component
public class MonthSalesStockReportServiceImpl implements MonthSalesStockReportQueryService {

    private final String GROUPBY_BUSINESSUNIT = "org_business_unit_id";
    private final String GROUPBY_CATEGORY = "sc_item_root_category_id";

    @Resource
    MonthSalesStockReportQueryRepository monthSalesStockReportQueryRepository;

    @Resource
    EpochCacheService epochCacheService;

    @Override
    public Result<List<MonthSalesStockReportVO>> pageQueryMonthSalesStockReportList(QueryMonthStockReportRequest queryMonthStockReportRequest) {
        if(StringUtil.isBlank(queryMonthStockReportRequest.getStatisticalDate())){
            throw new FacadeException(ErrorMessage.code("OTS-01-010-01-15-001"));
        }
        if(queryMonthStockReportRequest.getStart()==null){
            queryMonthStockReportRequest.setStart(0);
        }
        if(queryMonthStockReportRequest.getLimit()==null){
            queryMonthStockReportRequest.setLimit(10);
        }
        PageResult<List<MonthSalesStockReportSDO>> pageResult = monthSalesStockReportQueryRepository.pageQueryMonthSalesStockReportList(queryMonthStockReportRequest);
        List<MonthSalesStockReportSDO> listResult = pageResult.getContent();
        List<MonthSalesStockReportVO> converterResult = null;
        Result<List<SubtotalViewVO>> viewResult = null;
        String progressValue = DomUtil.getProgressValue(queryMonthStockReportRequest.getStatisticalDate());
        progressValue = progressValue.substring(0,progressValue.length()-1);
        //查询为空，初始化列表数据
        if(CollectionUtils.isEmpty(listResult)){
            converterResult = new ArrayList<>();
            viewResult = initSubtotalViewVO();
        }else{
            //填充分子公司品类小记，分子公司合计
            insertTotalRow(listResult,queryMonthStockReportRequest);
            //数据格式转换
            converterResult = converterVO(listResult,progressValue);
            //查询表头的数据统计
            Result<List<SubtotalViewVO>> response = getSubtotalViewData(queryMonthStockReportRequest);
            viewResult = response;
        }
        Map<String,Object> ext = new HashMap<>();
        ext.put("statistic", viewResult.getResult());
        ext.put("progress", progressValue);
        ext.put("reportUpdateTime", getReportUpdateTime(queryMonthStockReportRequest.getStatisticalDate(),queryMonthStockReportRequest.getOrgBusinessUnitIds()));
        Result result = Result.listSuccess(converterResult,pageResult.getTotal());
        result.setExt(ext);
        return result;
    }

    private String getReportUpdateTime(String statisticalDate, List<String> orgBusinessUnitIds){
        String today = DomUtil.getToday();
        if(!today.equals(statisticalDate)){
            return "—";
        }
        String text = "上次更新时间：";
        String json = epochCacheService.get(OtsApplicationReportSdkConstants.REDIS_CACHE_CODE(), MonthSalesStockReportSyncJob.RUNNING_TASK_REDIS_KEY);
        List<String> queryOrgsTaskData = new ArrayList<>();
        if(StringUtils.isNotBlank(json)){
            queryOrgsTaskData = JSONObject.parseObject(json, List.class);
        }

        if(CollectionUtils.isNotEmpty(orgBusinessUnitIds)) {
            queryOrgsTaskData = queryOrgsTaskData.stream().filter(x -> {
                String[] runningData = x.split("#");
                if (orgBusinessUnitIds.contains(runningData[0])) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
        }

        List<String> reportCompleteTime = new ArrayList<>();
        for (String data : queryOrgsTaskData) {
            String[] runningData = data.split("#");
            if(runningData.length>3 && StringUtils.isNotBlank(runningData[3])
                    && today.equals(DateUtils.string2String(runningData[3]))){
                reportCompleteTime.add(runningData[3]);
            }
        }

        reportCompleteTime = reportCompleteTime.stream().sorted((s1,s2) -> {
            if(DateUtils.string2Date(s1,DateUtils.DATETIME_FORMAT).before(DateUtils.string2Date(s2,DateUtils.DATETIME_FORMAT))){
                return -1;
            }else{
                return 1;
            }
        }).collect(Collectors.toList());

        if(CollectionUtils.isNotEmpty(reportCompleteTime)){
            return text+reportCompleteTime.get(0);
        }
        return text;
    }

    private List<MonthSalesStockReportVO> converterVO(List<MonthSalesStockReportSDO> list,String progressValue){
        List<MonthSalesStockReportVO> result = list.stream().map( x -> {
            MonthSalesStockReportVO vo = new MonthSalesStockReportVO();
            BeanUtils.copyProperties(x,vo);
            if(StringUtils.isNotBlank(x.getScItemGuaranteePeriodType())){
                ScItemGuaranteePeriodTypeEnum typeEnum = ScItemGuaranteePeriodTypeEnum.of(x.getScItemGuaranteePeriodType());
                if(typeEnum != null){
                    vo.setScItemGuaranteePeriodTypeName(typeEnum.getLabel());
                }
            }
            vo.setMonthContractQuantity(divideThousand(x.getMonthContractQuantity()));
            vo.setMonthPlanReplyQuantity(divideThousand(x.getMonthPlanReplyQuantity()));
            vo.setMonthAllocateOrderQuantity(divideThousand(x.getMonthAllocateOrderQuantity()));
            vo.setMonthAllocateUnshippedQuantity(divideThousand(x.getMonthAllocateUnshippedQuantity()));
            vo.setMonthAllocateUnconfirmedQuantity(divideThousand(x.getMonthAllocateUnconfirmedQuantity()));
            vo.setMonthAllocateReceivingQuantity(divideThousand(x.getMonthAllocateReceivingQuantity()));
            vo.setMonthAllocateOnWayQuantity(divideThousand(x.getMonthAllocateOnWayQuantity()));
            vo.setDaySalesOrderQuantity(divideThousand(x.getDaySalesOrderQuantity(),3));
            vo.setMonthSalesOrderQuantity(divideThousand(x.getMonthSalesOrderQuantity(),3));
            vo.setInventoryQuantity(divideThousand(x.getInventoryQuantity(),3));

            if(x.getMonthPlanReplyQuantity()!=null && x.getMonthPlanReplyQuantity()!=0){
                BigDecimal monthQuantityComplete = new BigDecimal(x.getMonthAllocateOrderQuantity())
                        .divide(new BigDecimal(x.getMonthPlanReplyQuantity()),4,RoundingMode.HALF_UP);
                vo.setMonthCompleteTag(String.valueOf(monthQuantityComplete.multiply(DomUtil.ONE_HUNDRED).compareTo(new BigDecimal(progressValue))));
                vo.setMonthCompletePercentage(DomUtil.percentFormat(monthQuantityComplete));
            }else{
                vo.setMonthCompletePercentage("/");
            }

            Long monthAllocateOrderQuantity = x.getMonthAllocateOrderQuantity()==null?0L:x.getMonthAllocateOrderQuantity();
            Long monthPlanReplyQuantity = x.getMonthPlanReplyQuantity()==null?0L:x.getMonthPlanReplyQuantity();
            BigDecimal monthQuantityRemain = new BigDecimal(monthAllocateOrderQuantity).subtract(new BigDecimal(monthPlanReplyQuantity));
            vo.setMonthQuantityRemain(divideThousand(monthQuantityRemain.longValue()));

            if(StringUtils.isNotBlank(x.getInventoryProductionDate())){
                List<String> inventoryProductionDate = JSONObject.parseObject(x.getInventoryProductionDate(),List.class);
                inventoryProductionDate = inventoryProductionDate.size()>10?inventoryProductionDate.subList(0,10):inventoryProductionDate;
                vo.setInventoryProductionDate(formatProductionDateString(inventoryProductionDate));
            }
            return vo;
        }).collect(Collectors.toList());
        return result;
    }

    private void insertTotalRow(List<MonthSalesStockReportSDO> listResult, QueryMonthStockReportRequest queryRequest){
        List<MonthSalesStockReportSDO> newListResult = Lists.newArrayList(listResult);
        //id , type, index
        Map<String,List<Object>> ids = new LinkedHashMap<>();
        int insertTimes = 0;
        String lastBusinessUnitId = listResult.get(0).getOrgBusinessUnitId();
        String lastCategoryId = lastBusinessUnitId+listResult.get(0).getScItemRootCategoryId();

        //查询下一页的List第一个
        QueryMonthStockReportRequest nextPageRequest = new QueryMonthStockReportRequest();
        BeanUtils.copyProperties(queryRequest,nextPageRequest);
        nextPageRequest.setStart(queryRequest.getStart()+queryRequest.getLimit());
        PageResult<List<MonthSalesStockReportSDO>> pageResult = monthSalesStockReportQueryRepository.pageQueryMonthSalesStockReportList(nextPageRequest);
        if(CollectionUtils.isNotEmpty(pageResult.getContent())){
            newListResult.add(pageResult.getContent().get(0));
        }else{
            MonthSalesStockReportSDO bean = new MonthSalesStockReportSDO();
            bean.setScItemRootCategoryId("-1");
            bean.setOrgBusinessUnitId("-1");
            newListResult.add(bean);
        }

        Boolean needCategoryTotal = false;
        Boolean needBusinessUnitTotal = false;
        //计算出本次查询List，小计插入的位置
        for(int i = 0; i < newListResult.size(); i++){
            MonthSalesStockReportSDO temp = newListResult.get(i);
            if(!lastCategoryId.equals(temp.getOrgBusinessUnitId()+temp.getScItemRootCategoryId())){
                ids.put(lastCategoryId,Lists.newArrayList(GROUPBY_CATEGORY,i+insertTimes));
                lastCategoryId = temp.getOrgBusinessUnitId()+temp.getScItemRootCategoryId();
                insertTimes++;
                needCategoryTotal = true;
            }
            if(!lastBusinessUnitId.equals(temp.getOrgBusinessUnitId())){
                ids.put(lastBusinessUnitId,Lists.newArrayList(GROUPBY_BUSINESSUNIT,i+insertTimes));
                lastBusinessUnitId = temp.getOrgBusinessUnitId();
                insertTimes++;
                needBusinessUnitTotal = true;
            }
        };

        Map<String,MonthSalesStockReportSDO> categoryMap = null;
        Map<String,MonthSalesStockReportSDO> businessUnitMap = null;
        //分子公司品类小计
        if(needCategoryTotal){
            queryRequest.setGroupBy(GROUPBY_CATEGORY);
            List<MonthSalesStockReportSDO> categoryList = monthSalesStockReportQueryRepository.statisticalQuery(queryRequest);
            categoryMap = categoryList.stream().collect(Collectors.toMap(x->x.getOrgBusinessUnitId()+x.getScItemRootCategoryId(), Function.identity(),(v1, v2)->v1));
        }
        //分子公司合计
        if(needBusinessUnitTotal){
            queryRequest.setGroupBy(GROUPBY_BUSINESSUNIT);
            List<MonthSalesStockReportSDO> businessUnitList = monthSalesStockReportQueryRepository.statisticalQuery(queryRequest);
            businessUnitMap = businessUnitList.stream().collect(Collectors.toMap(MonthSalesStockReportSDO::getOrgBusinessUnitId, Function.identity(),(v1, v2)->v1));
        }

        //listResult插入品类小计，分子公司合计
        for (Map.Entry<String, List<Object>> m : ids.entrySet()) {
            List<Object> tmp = m.getValue();
            if(needCategoryTotal && tmp.get(0).equals(GROUPBY_CATEGORY)){
                MonthSalesStockReportSDO row = categoryMap.get(m.getKey());
                row.setScItemRootCategoryName("品类小记");
                listResult.add((int)tmp.get(1),row);
            }else if(needBusinessUnitTotal && tmp.get(0).equals(GROUPBY_BUSINESSUNIT)){
                MonthSalesStockReportSDO row = businessUnitMap.get(m.getKey());
                row.setOrgBusinessUnitName("分子公司合计");
                listResult.add((int)tmp.get(1),row);
            }
        }
    }

    private Result<List<SubtotalViewVO>> getSubtotalViewData(QueryMonthStockReportRequest queryRequest){
        if(queryRequest.getIsExcel()!=null && queryRequest.getIsExcel()){
            return Result.listSuccess(null,0);
        }
        queryRequest.setGroupBy(null);
        List<MonthSalesStockReportSDO> result = monthSalesStockReportQueryRepository.statisticalQuery(queryRequest);
        MonthSalesStockReportSDO sdo = new MonthSalesStockReportSDO();
        if(CollectionUtils.isEmpty(result)){
            sdo.setMonthContractQuantity(0L);
            sdo.setMonthPlanReplyQuantity(0L);
            sdo.setMonthAllocateOrderQuantity(0L);
            sdo.setMonthAllocateUnshippedQuantity(0L);
            sdo.setMonthAllocateUnconfirmedQuantity(0L);
            sdo.setMonthAllocateReceivingQuantity(0L);
            sdo.setMonthAllocateOnWayQuantity(0L);
            sdo.setDaySalesOrderQuantity(0L);
            sdo.setMonthSalesOrderQuantity(0L);
            sdo.setInventoryQuantity(0L);
        }else{
            sdo = result.get(0);
        }

        //SubtotalViewVO column1 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("月合同量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthContractQuantity()));
        SubtotalViewVO column2 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("月回复量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthPlanReplyQuantity()));
        SubtotalViewVO column3 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("累计下单量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthAllocateOrderQuantity()));
        //SubtotalViewVO column6 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("已审未发",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthAllocateUnshippedQuantity()));
        //SubtotalViewVO column7 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("未审",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthAllocateUnconfirmedQuantity()));
        //SubtotalViewVO column8 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("到货量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthAllocateReceivingQuantity()));
        //SubtotalViewVO column9 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("在途",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthAllocateOnWayQuantity()));
        SubtotalViewVO column10 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("今日出库数量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getDaySalesOrderQuantity(),3));
        SubtotalViewVO column11 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("当月累计出库数",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getMonthSalesOrderQuantity(),3));
        SubtotalViewVO column12 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("今日合计库存",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(sdo.getInventoryQuantity(),3));

//        SubtotalViewVO column4 = new SubtotalViewVO();
//        if(sdo.getMonthPlanReplyQuantity()!=null && sdo.getMonthPlanReplyQuantity()!=0){
//            BigDecimal monthQuantityComplete = new BigDecimal(sdo.getMonthAllocateOrderQuantity())
//                    .divide(new BigDecimal(sdo.getMonthPlanReplyQuantity()),4,RoundingMode.HALF_UP)
//                    .multiply(DomUtil.ONE_HUNDRED).setScale(2);
//            column4 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("累计达成率",SubtotalViewVOUtil.PERCENT,monthQuantityComplete);
//        }else{
//            column4.setLabel("累计达成率");
//            column4.setValue(" / ");
//        }

        Long monthAllocateOrderQuantity = sdo.getMonthAllocateOrderQuantity()==null?0L:sdo.getMonthAllocateOrderQuantity();
        Long monthPlanReplyQuantity = sdo.getMonthPlanReplyQuantity()==null?0L:sdo.getMonthPlanReplyQuantity();
        BigDecimal monthQuantityRemain = new BigDecimal(monthAllocateOrderQuantity).subtract(new BigDecimal(monthPlanReplyQuantity));
        SubtotalViewVO column5 = SubtotalViewVOUtil.getSubtotalVODeltaNoFormat("月进度差量",SubtotalViewVOUtil.JIAN,divideThousandGetBigDecimal(monthQuantityRemain.longValue()));

        List<SubtotalViewVO> subtotalViewVOList = Lists.newArrayList(column2,column3,column5,column10,column11,column12);
        return Result.listSuccess(subtotalViewVOList,subtotalViewVOList.size());
    }

    private Result<List<SubtotalViewVO>> initSubtotalViewVO(){
//        SubtotalViewVO column1 = new SubtotalViewVO();
//        column1.setLabel("月合同量");
//        column1.setValue("0");
//        column1.setUnit("件");
        SubtotalViewVO column2 = new SubtotalViewVO();
        column2.setLabel("月回复量");
        column2.setValue("0");
        column2.setUnit("件");
        SubtotalViewVO column3 = new SubtotalViewVO();
        column3.setLabel("累计下单量");
        column3.setValue("0");
        column3.setUnit("件");
//        SubtotalViewVO column4 = new SubtotalViewVO();
//        column4.setLabel("累计达成率");
//        column4.setValue("/");
        SubtotalViewVO column5 = new SubtotalViewVO();
        column5.setLabel("月进度差量");
        column5.setValue("0");
        column5.setUnit("件");
//        SubtotalViewVO column6 = new SubtotalViewVO();
//        column6.setLabel("已审未发");
//        column6.setValue("0");
//        column6.setUnit("件");
//        SubtotalViewVO column7 = new SubtotalViewVO();
//        column7.setLabel("未审");
//        column7.setValue("0");
//        column7.setUnit("件");
//        SubtotalViewVO column8 = new SubtotalViewVO();
//        column8.setLabel("到货量");
//        column8.setValue("0");
//        column8.setUnit("件");
//        SubtotalViewVO column9 = new SubtotalViewVO();
//        column9.setLabel("在途");
//        column9.setValue("0");
//        column9.setUnit("件");
        SubtotalViewVO column10 = new SubtotalViewVO();
        column10.setLabel("今日出库数量");
        column10.setValue("0");
        column10.setUnit("件");
        SubtotalViewVO column11 = new SubtotalViewVO();
        column11.setLabel("当月累计出库数量");
        column11.setValue("0");
        column11.setUnit("件");
        SubtotalViewVO column12 = new SubtotalViewVO();
        column12.setLabel("今日合计库存");
        column12.setValue("0");
        column12.setUnit("件");

        List<SubtotalViewVO> list = Lists.newArrayList(column2,column3,column5,column10,column11,column12);
        Result result = Result.listSuccess(list,list.size());
        return result;
    }

    private String divideThousand(Long quantity){
        if(quantity == null){
            return BigDecimal.ZERO.toString();
        }
        BigDecimal bigDecimal = new BigDecimal(quantity).divide(DomUtil.ONE_THOUSAND_BIGDECIMAL,2, RoundingMode.HALF_UP);
        return bigDecimal.toString();
    }

    private String divideThousand(Long quantity,int scale){
        if(quantity == null){
            return BigDecimal.ZERO.toString();
        }
        BigDecimal bigDecimal = new BigDecimal(quantity).divide(DomUtil.ONE_THOUSAND_BIGDECIMAL,scale, RoundingMode.HALF_UP);
        return bigDecimal.toString();
    }

    private BigDecimal divideThousandGetBigDecimal(Long quantity){
        if(quantity == null){
            return BigDecimal.ZERO;
        }
        BigDecimal bigDecimal = new BigDecimal(quantity).divide(DomUtil.ONE_THOUSAND_BIGDECIMAL,2, RoundingMode.HALF_UP);
        return bigDecimal;
    }

    private BigDecimal divideThousandGetBigDecimal(Long quantity,int scale){
        if(quantity == null){
            return BigDecimal.ZERO;
        }
        BigDecimal bigDecimal = new BigDecimal(quantity).divide(DomUtil.ONE_THOUSAND_BIGDECIMAL,scale, RoundingMode.HALF_UP);
        return bigDecimal;
    }

    private String formatProductionDateString(List<String> dates){
        String dateStr = JSONObject.toJSONString(dates);
        dateStr = dateStr.substring(2,dateStr.length()-2);
        String[] dateArray = dateStr.split("\",\"");
        String result = "";
        for (String date:dateArray) {
            result +=date+";";
        }
        return result;
    }
}
